﻿
using MicroApi.Core.Filters;

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;

using Newtonsoft.Json.Serialization;

using System;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
using Utils;
using Utils.Cache;
using Utils.Http;
using Utils.JobTask;


namespace Microsoft.Extensions.DependencyInjection
{
    public static class MicroApiServicesExtensions
    {
        public static IServiceCollection ConfigureWritable<T>(this IServiceCollection services, IConfigurationSection section, string fileName = "appsettings") where T : class, new()
        {
            services.Configure<T>(section);
            services.AddTransient<IWritableOptions<T>>(provider =>
            {
                var environment = provider.GetService<IWebHostEnvironment>();
                var options = provider.GetService<IOptionsMonitor<T>>();
                return new WritableOptions<T>(environment, options, section.Key, fileName);
            });
            return services;
        }

        public static IServiceCollection AddUtilsDefault(this IServiceCollection services)
        {
            services.AddJob();
            services.AddInjection();
            services.AddLazyService();
            services.AddLogging(); 
            services.AddTransient<ConfigService>();
            services.AddScoped(services => new HttpClient(new DefaultHttpHandler()));
            services.AddTransient(typeof(AutoCacheQueryable<>));
            return services;
        }
        public static IServiceCollection AddDefaultCache(this IServiceCollection services)
        {
            services.AddMemoryCache();
            return services.AddSingleton<ICacheStrategy, MemoryCacheStrategy>();
        }

        /// <summary>
        /// 临时存储
        /// </summary>
        /// <param name="webHostEnvironment"></param>
        /// <param name="fileName"></param>
        /// <param name="path"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static async Task<Stream> GetOrSave(this IWebHostEnvironment webHostEnvironment, string path, string fileName, Func<Task<Stream>> func)
        {
            string webRootPath = webHostEnvironment.WebRootPath;
            var filePath = Path.Combine(path, fileName);
            var fileInfo = webHostEnvironment.WebRootFileProvider.GetFileInfo(filePath);
            if (fileInfo.Exists)
            {
                return fileInfo.CreateReadStream();
            }
            var stream = await func();
            try
            {
                Console.WriteLine("{0},{1}", webRootPath, filePath);
                await stream.SaveAsync(fileName, webRootPath, path);
                stream.Seek(0, SeekOrigin.Begin);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            return stream;
        }



        /// <summary>
        /// 添加默认配置
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IMvcBuilder AddApiConfig(this IServiceCollection services, params string[] ignores)
        {
            var mvc = services
                  .AddControllers(options =>
                  {
                      options.Filters.Add<AuthorizationFilter>();
                      options.Filters.Add<ExceptionFilter>();
                      options.Filters.Add<ActionResultFilter>();

                  })
                  .AddNewtonsoftJson(options =>
                  {
                      options.SerializerSettings.DateFormatString = JsonHelper.DefaultJsonSerializerSettings.DateFormatString;
                      options.SerializerSettings.NullValueHandling = JsonHelper.DefaultJsonSerializerSettings.NullValueHandling;
                      options.SerializerSettings.ContractResolver = JsonHelper.DefaultJsonSerializerSettings.ContractResolver;
                      options.SerializerSettings.Converters = JsonHelper.DefaultJsonSerializerSettings.Converters;
                      options.SerializerSettings.Formatting = JsonHelper.DefaultJsonSerializerSettings.Formatting;
                      options.SerializerSettings.FloatFormatHandling = JsonHelper.DefaultJsonSerializerSettings.FloatFormatHandling;

                  })
                  .ConfigureApiBehaviorOptions(options =>
                  {
                      options.SuppressModelStateInvalidFilter = false;
                  });


            return mvc;
        }

        /// <summary>
        /// 使用默认配置
        /// </summary>
        /// <param name="app"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseApiConfig(this IApplicationBuilder app)
        {
            IWebHostEnvironment env = app.ApplicationServices.GetService<IWebHostEnvironment>();
            AutoCacheQueryable.Init(app.ApplicationServices);
            var webRootPath = app.ApplicationServices.GetService<IConfiguration>().GetValue<string>("WebRootPath");
            if (!string.IsNullOrEmpty(webRootPath))
                env.WebRootPath = Path.Combine(env.ContentRootPath, webRootPath);
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseStatusCodePages();
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
            return app;
        }
         

        /// <summary>
        /// 启用任务
        /// </summary>
        /// <param name="app"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseJob(this IApplicationBuilder app)
        {
            return app.UseJob(null);
        }

        /// <summary>
        /// 启用任务
        /// </summary>
        /// <param name="app"></param>
        /// <param name="configJobs"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseJob(this IApplicationBuilder app, Action<JobTaskBuilder> configJobs)
        {
            var jobService = app.ApplicationServices.GetRequiredService<IJobProvider>();
            JobTaskBuilder jobBuilder = new JobTaskBuilder();
            configJobs?.Invoke(jobBuilder);
            jobService.Run(jobBuilder);
            return app;
        }
    }
}
